/**
 * 混合图表组件（可复用）
 */

import React from 'react';
import { Chart as ChartJS, CategoryScale, LinearScale, RadialLinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend, Filler } from 'chart.js';
import { Chart, Radar } from 'react-chartjs-2';

ChartJS.register(
  CategoryScale,
  LinearScale,
  RadialLinearScale,
  PointElement,
  LineElement,
  BarElement,
  ArcElement,
  Title,
  Tooltip,
  Legend,
  Filler
);

interface MixedChartProps {
  data: {
    labels: (string | number)[];
    datasets: Array<{
      label: string;
      data: number[];
      type: string; // 允许多种类型：line/bar/area/scatter/stacked/...
      backgroundColor?: string | string[];
      borderColor?: string;
      borderWidth?: number;
      borderDash?: number[];
      fill?: boolean;
      tension?: number;
      pointRadius?: number;
      pointStyle?: any;
      yAxisID?: string;
      stack?: string; // 堆叠图的 stack 属性
      stepped?: boolean; // 阶梯折线
    }>;
  };
  options?: any;
  height?: number;
}

const MixedChart: React.FC<MixedChartProps> = React.memo(({ data, options, height = 400 }) => {
  const builtDatasets: any[] = [];
  data.datasets.forEach((dataset) => {
    const baseConfig: any = {
      label: dataset.label,
      data: dataset.data,
      backgroundColor: dataset.backgroundColor,
      borderColor: dataset.borderColor,
      borderWidth: dataset.borderWidth || 2,
      borderDash: dataset.borderDash,
      yAxisID: dataset.yAxisID || 'y',
      stack: dataset.stack,
      stepped: dataset.stepped,
      pointStyle: (dataset as any).pointStyle,
    };

    switch (dataset.type) {
      case 'line':
        builtDatasets.push({
          ...baseConfig,
          type: 'line',
          fill: dataset.fill || false,
          tension: dataset.stepped ? 0 : (dataset.tension || 0.1),
          stepped: (dataset.stepped === true || typeof (dataset as any).stepped === 'string') ? (dataset as any).stepped : undefined,
          pointRadius: dataset.pointRadius !== undefined ? dataset.pointRadius : 3,
          pointHoverRadius: 5,
          borderJoinStyle: 'round',
          pointStyle: baseConfig.pointStyle,
        });
        break;

      case 'bar':
        builtDatasets.push({
          ...baseConfig,
          type: 'bar',
          backgroundColor: dataset.backgroundColor || 'rgba(54, 162, 235, 0.6)',
          borderColor: dataset.borderColor || 'rgba(54, 162, 235, 1)',
          borderRadius: 4,
        });
        break;

      case 'area':
        builtDatasets.push({
          ...baseConfig,
          type: 'line',
          fill: true,
          tension: dataset.tension || 0.4,
          pointRadius: dataset.pointRadius !== undefined ? dataset.pointRadius : 0,
          pointHoverRadius: 4,
        });
        break;

      case 'scatter':
        builtDatasets.push({
          ...baseConfig,
          type: 'line',
          pointRadius: dataset.pointRadius !== undefined ? dataset.pointRadius : 4,
          pointHoverRadius: 6,
          pointStyle: baseConfig.pointStyle,
          showLine: false,
          data: (dataset.data || []).map((value, index) => ({ x: index, y: value })),
        });
        break;

      case 'stacked':
        builtDatasets.push({
          ...baseConfig,
          type: 'bar',
          backgroundColor: dataset.backgroundColor || 'rgba(54, 162, 235, 0.6)',
          borderColor: dataset.borderColor || 'rgba(54, 162, 235, 1)',
          borderRadius: 4,
          stack: dataset.stack || 'stack1',
        });
        break;

      case 'stacked-line':
        builtDatasets.push({
          ...baseConfig,
          type: 'line',
          fill: false,
          tension: dataset.tension || 0.1,
          pointRadius: dataset.pointRadius !== undefined ? dataset.pointRadius : 3,
          pointHoverRadius: 5,
          stack: dataset.stack || 'stack1',
        });
        break;

      case 'stacked-area':
        builtDatasets.push({
          ...baseConfig,
          type: 'line',
          fill: true,
          tension: dataset.tension || 0.4,
          pointRadius: dataset.pointRadius !== undefined ? dataset.pointRadius : 0,
          pointHoverRadius: 4,
          stack: dataset.stack || 'stack1',
        });
        break;

      case 'pie':
        builtDatasets.push({ ...baseConfig, type: 'pie' });
        break;

      case 'doughnut':
        builtDatasets.push({ ...baseConfig, type: 'doughnut' });
        break;

      case 'radar':
        builtDatasets.push({
          ...baseConfig,
          type: 'radar',
          fill: (dataset as any).fill !== undefined ? (dataset as any).fill : true,
          pointRadius: dataset.pointRadius !== undefined ? dataset.pointRadius : 4,
          pointHoverRadius: 6,
          pointBackgroundColor: dataset.borderColor || baseConfig.borderColor,
          pointBorderColor: '#fff',
          pointHoverBackgroundColor: '#fff',
          pointHoverBorderColor: dataset.borderColor || baseConfig.borderColor,
        });
        break;

      default:
        builtDatasets.push({ ...baseConfig, type: 'line' });
        break;
    }
  });

  const chartData = { labels: data.labels, datasets: builtDatasets } as any;
  const hasStackedData = chartData.datasets.some((ds: any) => ds.stack);
  const hasPieOrDoughnut = chartData.datasets.some((ds: any) => ds.type === 'pie' || ds.type === 'doughnut');
  const hasRadar = chartData.datasets.some((ds: any) => ds.type === 'radar');
  const chartType = hasPieOrDoughnut && chartData.datasets.length === 1 
    ? chartData.datasets[0].type 
    : hasRadar 
    ? 'radar' 
    : 'bar';

  // 若为雷达图，计算步长与 r 轴范围（中心为最小刻度 - 步长）
  let radarScale: any = undefined;
  if (hasRadar) {
    const allValues: number[] = [];
    (chartData.datasets || []).forEach((ds: any) => {
      if (Array.isArray(ds.data)) {
        ds.data.forEach((v: any) => {
          const num = typeof v === 'number' ? v : Number(v);
          if (!Number.isNaN(num)) allValues.push(num);
        });
      }
    });
    const dMin = allValues.length ? Math.min(...allValues) : 0;
    const dMax = allValues.length ? Math.max(...allValues) : 1;
    const rng = Math.max(1e-9, dMax - dMin);
    const niceStep = (r: number): number => {
      const targetTicks = 5;
      const rough = r / targetTicks;
      const pow10 = Math.pow(10, Math.floor(Math.log10(rough)));
      const candidates = [1, 2, 5, 10].map(m => m * pow10);
      let best = candidates[0];
      let bestDiff = Math.abs(candidates[0] - rough);
      for (let i = 1; i < candidates.length; i++) {
        const diff = Math.abs(candidates[i] - rough);
        if (diff < bestDiff) { best = candidates[i]; bestDiff = diff; }
      }
      return best > 0 ? best : pow10;
    };
    const step = niceStep(rng);
    const minTick = Math.floor(dMin / step) * step;
    const rMin = Math.max(0, minTick - step); // 中心应为最小刻度减去一个步长，但不小于0
    const rMax = Math.ceil(dMax / step) * step;
    radarScale = { r: {
      min: Number.isFinite(rMin) ? rMin : undefined,
      max: Number.isFinite(rMax) ? rMax : undefined,
      angleLines: { color: 'rgba(0, 0, 0, 0.1)' },
      grid: { color: 'rgba(0, 0, 0, 0.1)' },
      pointLabels: { font: { size: 12 } },
      ticks: { backdropColor: 'transparent', beginAtZero: false, stepSize: step },
    }, x: { display: false }, y: { display: false } };
  }

  const defaultOptions = {
    responsive: true,
    maintainAspectRatio: false,
    interaction: { 
      mode: hasPieOrDoughnut ? 'point' as const : hasRadar ? 'point' as const : ('index' as const), 
      intersect: hasRadar ? false : false 
    },
    plugins: {
      legend: { position: 'top' as const, labels: { usePointStyle: true, padding: 15, font: { size: 12 } } },
      tooltip: {
        backgroundColor: 'rgba(0, 0, 0, 0.8)',
        padding: 12,
        titleFont: { size: 14 },
        bodyFont: { size: 12 },
        callbacks: {
          label: function(context: any) {
            let label = context.dataset.label || '';
            if (label) label += ': ';
            if (hasRadar) {
              const value = context.parsed?.r ?? context.raw ?? 0;
              label += Number((Number(value)).toFixed(2)).toLocaleString();
            } else if (context.parsed.y !== null) {
              label += Number(context.parsed.y.toFixed(2)).toLocaleString();
            }
            return label;
          },
        },
      },
    },
    scales: hasRadar ? (radarScale || { r: {}, x: { display: false }, y: { display: false } }) : {
      x: { display: !hasPieOrDoughnut, stacked: hasStackedData, title: { display: true, text: '索引', font: { size: 12 } }, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' } },
      y: { display: !hasPieOrDoughnut, stacked: hasStackedData, beginAtZero: hasStackedData, title: { display: true, text: '数值', font: { size: 12 } }, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' } },
    },
    ...options,
  } as any;

  // 雷达图使用 Radar 组件，其他图表使用 Chart 组件
  if (hasRadar) {
    return (
      <div style={{ width: '100%', height: `${height}px`, position: 'relative' }}>
        <Radar data={chartData} options={defaultOptions} />
      </div>
    );
  }

  return (
    <div style={{ width: '100%', height: `${height}px`, position: 'relative' }}>
      <Chart type={chartType as any} data={chartData} options={defaultOptions} />
    </div>
  );
}, (prevProps, nextProps) => {
  if (prevProps.height !== nextProps.height) return false;
  if (prevProps.data === nextProps.data) return true;
  if (!prevProps.data || !nextProps.data) return prevProps.data === nextProps.data;
  const prevLabels = prevProps.data.labels || [];
  const nextLabels = nextProps.data.labels || [];
  if (prevLabels.length !== nextLabels.length) return false;
  if (prevLabels.some((label, i) => label !== nextLabels[i])) return false;
  const prevDatasets = prevProps.data.datasets || [];
  const nextDatasets = nextProps.data.datasets || [];
  if (prevDatasets.length !== nextDatasets.length) return false;
  for (let i = 0; i < prevDatasets.length; i++) {
    const prevDs: any = prevDatasets[i];
    const nextDs: any = nextDatasets[i];
    if (prevDs.label !== nextDs.label || prevDs.type !== nextDs.type || prevDs.stack !== nextDs.stack) return false;
    const prevData = Array.isArray(prevDs.data) ? prevDs.data : [];
    const nextData = Array.isArray(nextDs.data) ? nextDs.data : [];
    if (prevData.length !== nextData.length) return false;
    if (prevData.length === 0) continue;
    const sampleSize = Math.min(100, prevData.length);
    for (let j = 0; j < sampleSize; j++) {
      const prevVal = prevData[j];
      const nextVal = nextData[j];
      if (typeof prevVal === 'object' && typeof nextVal === 'object' && prevVal && nextVal && 'x' in prevVal && 'y' in prevVal && 'x' in nextVal && 'y' in nextVal) {
        if ((prevVal as any).x !== (nextVal as any).x || (prevVal as any).y !== (nextVal as any).y) return false;
      } else if (prevVal !== nextVal) {
        return false;
      }
    }
    if (prevData.length > sampleSize) {
      const endStart = Math.max(sampleSize, prevData.length - 10);
      for (let j = endStart; j < prevData.length; j++) {
        const prevVal = prevData[j];
        const nextVal = nextData[j];
        if (typeof prevVal === 'object' && typeof nextVal === 'object' && prevVal && nextVal && 'x' in prevVal && 'y' in prevVal && 'x' in nextVal && 'y' in nextVal) {
          if ((prevVal as any).x !== (nextVal as any).x || (prevVal as any).y !== (nextVal as any).y) return false;
        } else if (prevVal !== nextVal) {
          return false;
        }
      }
    }
    // 比较样式相关关键字段，发生变化则需要重绘
    if (prevDs.backgroundColor !== nextDs.backgroundColor || prevDs.borderColor !== nextDs.borderColor) return false;
    if (prevDs.borderWidth !== nextDs.borderWidth) return false;
    if (prevDs.tension !== nextDs.tension) return false;
    if (prevDs.pointRadius !== nextDs.pointRadius) return false;
    if (prevDs.pointStyle !== nextDs.pointStyle) return false;
    const prevDash = Array.isArray(prevDs.borderDash) ? prevDs.borderDash.join(',') : String(prevDs.borderDash);
    const nextDash = Array.isArray(nextDs.borderDash) ? nextDs.borderDash.join(',') : String(nextDs.borderDash);
    if (prevDash !== nextDash) return false;
    if (prevDs.stepped !== nextDs.stepped) return false;
  }
  return true;
});

MixedChart.displayName = 'MixedChart';

export default MixedChart;


